package com.seo.proxy.http;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringUtils;

import com.seo.proxy.Buffer;
import com.seo.proxy.context.RequestContext;
import com.seo.proxy.context.RequestState;

public class HttpRequestParser {
	
	public boolean parseRequest(RequestContext requestContext) {
		HttpRequest httpRequest = requestContext.getHttpRequest();
		Buffer requestBuffer = requestContext.getRequestBuffer();
		RequestState requestState = requestContext.getRequestState();
		
		if (!requestState.isHeadersReceived()) {
			int endOfHeaders = getEndOfHeaders(requestBuffer);
			if (endOfHeaders > 0) {
				requestState.setHeadersReceived(true);
				requestState.setEndOfHeaders(endOfHeaders);
				String headers = requestBuffer.getString(0, endOfHeaders);
				requestContext.getHttpRequest().setRawHeaders(headers);
				parseHeaders(requestContext, headers);
				
				if (!requestState.isExpectingBody()) {
					requestBuffer.compact(endOfHeaders);
					return true;
				}
			}
		}
		if (requestState.isExpectingBody()) {
			if (requestBuffer.getPosition() - requestState.getEndOfHeaders() >= httpRequest.getContentLength()) {
				requestState.setExpectingBody(false);
				httpRequest.setBody(requestBuffer.getString(requestState.getEndOfHeaders(), httpRequest.getContentLength()));
				requestBuffer.compact(requestState.getEndOfHeaders() + httpRequest.getContentLength());
				return true;
			}
		}
		return false;
	}
	
	public void parseHeaders(RequestContext requestContext, String rawHeaders) {
		HttpRequest httpRequest = requestContext.getHttpRequest();
		RequestState requestState = requestContext.getRequestState();
		
		StringTokenizer st = new StringTokenizer(rawHeaders, "\r\n");
		boolean first = true;
		boolean keepConnection = false;
		while (st.hasMoreTokens()) {
			String line = st.nextToken();
			if (!first) {
				int pos = line.indexOf(":");
				if (pos > 0) {
					String name = line.substring(0, pos).trim();
					String value = line.substring(pos + 1).trim();
					Header header = new Header(name, value);

					if ("Content-Length".equalsIgnoreCase(name)) {
						httpRequest.setContentLengthHeader(header);
						int contentLength = Integer.parseInt(value);
						httpRequest.setContentLength(contentLength);
						requestState.setExpectingBody(contentLength > 0);
					} else if ("Content-Type".equalsIgnoreCase(name)) {
						httpRequest.setContentType(value);
					} else if ("Proxy-Connection".equalsIgnoreCase(name)) {
						if (!"keep-alive".equalsIgnoreCase(value)) {
							keepConnection = false;
						}
						continue;
					}
					httpRequest.getHeaders().add(header);
				}
			} else {
				first = false;
				parseRequestLine(requestContext, line);
				if ("http/1.1".equalsIgnoreCase(httpRequest.getProtocol())) {
					keepConnection = true;
				}
			}
		}
		httpRequest.setKeepConnection(keepConnection);
	}

	public void parseRequestLine(RequestContext requestContext, String line) {
		HttpRequest httpRequest = requestContext.getHttpRequest();
		httpRequest.setRequestLine(line);
		String[] parts = StringUtils.split(line, " ");
		httpRequest.setMethod(parts[0]);
		try {
			httpRequest.setUrl(new URL(parts[1]));
			httpRequest.setRawUrl(parts[1]);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		httpRequest.setProtocol(parts[2]);
	}

	public int getEndOfHeaders(Buffer buffer) {
		byte[] b = buffer.getBuffer();
		int b1 = buffer.getPosition() - 1;
		int b2 = buffer.getPosition() - 3;
		for (int i = 0; i < b1; i++) {
			if (i < b2 && b[i] == '\r' && b[i + 1] == '\n' && b[i + 2] == '\r' && b[i + 3] == '\n') {
				return i + 4;
			}
			if (b[i] == '\n' && b[i + 1] == '\n') {
				return i + 2;
			}
		}
		return -1;
	}
}
